package com.start.security.data.permission;

import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.start.common.constant.StartConstant;
import com.start.common.details.BaseUserDetails;
import com.start.common.exceptions.StartConflictException;
import com.start.common.tools.SpringContextTools;
import com.start.common.vo.SysMenuDataRulesVo;
import com.start.security.StartTokenTools;
import com.start.security.StartUserContext;
import com.start.security.StartUserContextManage;
import com.start.security.StartUserPermissionTools;
import com.start.security.annotations.DataPermission;
import com.start.security.annotations.IgnoreAuth;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 全局注入数据规则 以及规则值
 */
@Aspect
@Component
@Slf4j
public class DataPermissionInjector {

    @Autowired
    private StartUserPermissionTools userPermissionTools;




    @Pointcut("@annotation(com.start.security.annotations.DataPermission)")
    public void addAdvice() {
    }

    @Around("addAdvice()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        IgnoreAuth ignoreAuth = method.getAnnotation(IgnoreAuth.class);
        if (ignoreAuth != null)
            throw new StartConflictException(IgnoreAuth.class.getName() + "不能与" + DataPermission.class.getName() + "同时使用在：" + method.getName() + "上");
        DataPermission dataPermission = method.getAnnotation(DataPermission.class);
        if (StringUtils.isEmpty(dataPermission.value())) return point.proceed();
        HttpServletRequest request = SpringContextTools.getHttpServletRequest();
        BaseUserDetails currentUser = StartTokenTools.getCurrentUser();
        StartPermissionInjector injector = null;
        if (StringUtils.isEmpty(dataPermission.variable())) {
            injector = new DataStartPermissionComponentType(userPermissionTools);
        } else {
            injector = new DataStartPermissionComponentAndVariableType(userPermissionTools);
        }
        List<SysMenuDataRulesVo> rules = injector.getRules(request, currentUser, dataPermission);
        if (rules == null || rules.isEmpty()) return point.proceed();

        setDataPermissionContext(request, rules, currentUser, dataPermission);
        return point.proceed();
    }

    private void setDataPermissionContext(HttpServletRequest request, List<SysMenuDataRulesVo> rules, BaseUserDetails currentUser, DataPermission dataPermission) {
        /**
         * 标记该接口有数据规则
         */
        request.setAttribute(StartConstant.DataRule.key, dataPermission.value());
        StartUserContext userContext = StartUserContextManage.getInstance().getUserContext(currentUser);
        request.setAttribute("startUserContext", userContext);
        request.setAttribute(StartConstant.DataRule.userContextKey, JSONObject.toJSONString(userContext));
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(userContext));
        getDataRule(rules, jsonObject);
/**
 * 设置到当信息里面
 */
        request.setAttribute(StartConstant.DataRule.rulesKey, JSONObject.toJSONString(rules));
    }


    /**
     * 将数据规则中的全局变量替换成为实际值
     *
     * @param dataRulesVos
     * @param serverContext
     * @return
     */
    private void getDataRule(List<SysMenuDataRulesVo> dataRulesVos, JSONObject serverContext) {
        for (SysMenuDataRulesVo rulesVo : dataRulesVos) {
            String key = rulesVo.getRuleColumnValue();
            Object value = getRuleColumnValue(key, serverContext);
            if (value == null) {
                continue;
            }
            rulesVo.setRuleColumnValue(value.toString());
        }
    }



//    public static void main(String[] args) {
////       ;
//        System.out.println(  pattern.matcher("find_in_set ('#{prop.deptId}',patrol_group_ids)").find());
//        System.out.println( Pattern.matches("\\#\\{.*?\\}","find_in_set ('#{prop.deptId}',patrol_group_ids)") );
//    }
private static final Pattern pattern = Pattern.compile("\\#\\{.*?\\}");
    /**
     * 根据配置规则值处理规则值的最终值
     * 可以处理变量类型、嵌套变量类型以及非变量类型
     * 非变量类型 srcColumnKey =8
     * 变量类型 srcColumnKey=#{prop}
     * 嵌套变量类型 srcColumnKey=#{prop.sex} 或者 srcColumnKey=#{prop.dept.id}
     *
     * @param srcColumnKey 原始key
     * @param userContext  当前用户上下文对象
     * @return
     */
    private Object getRuleColumnValue(String srcColumnKey, JSONObject userContext) {
        if (!pattern.matcher(srcColumnKey).find()) { //检查该配置是否是变量类型#{user.id}
            return userContext.get(srcColumnKey);
        }
        List<String> allGroups = ReUtil.getAllGroups(pattern, srcColumnKey);
        for (String group : allGroups) {
            String columnKey = group.replace("#{", "").replace("}", "");
            if (userContext.containsKey(columnKey)) {
                srcColumnKey = srcColumnKey.replace(group, userContext.getString(columnKey));
                continue;
            }
            if (!columnKey.contains(".")) {
                continue;
            }
            Object value = getUserContextByKey(columnKey, columnKey, userContext);
            if (value == null) return null;
            if (!(value instanceof JSONArray)) {
                srcColumnKey = srcColumnKey.replace(group, value.toString());
                continue;
            }
            JSONArray array = (JSONArray) value;
            StringBuilder sb = new StringBuilder();
            for (Object o : array) {
                if (!sb.isEmpty()) {
                    sb.append(",");
                }
                sb.append(o.toString());
            }
            srcColumnKey = srcColumnKey.replace(group, sb);
        }
        return srcColumnKey;
    }

    /**
     * 根据用key户上下文对象 获取值 支持对象属性
     *
     * @param srcKey
     * @param key
     * @param userContext
     * @return
     */
    private Object getUserContextByKey(String srcKey, String key, JSONObject userContext) {
        if (!key.contains(".")) {
            return userContext.get(key);
        }
        int endKeyIndex = key.indexOf(".");
        String currentKey = key.substring(0, endKeyIndex);
        if (!userContext.containsKey(currentKey)) {
            log.warn("未能在用户上下文环境中找到 key:" + srcKey);
            return null;
        }
        JSONObject childrenContext = userContext.getJSONObject(currentKey);
        if (childrenContext.isEmpty()) {
            log.warn("未能在用户上下文环境中找到 key:" + srcKey);
            return null;
        }
        String newChildrenKey = key.substring(endKeyIndex + 1);
        return getUserContextByKey(srcKey, newChildrenKey, childrenContext);
    }

}
